﻿namespace Resharper.Abstractions.CodeDom.TypeMembers.Methods
{
  using System;
  using JetBrains.Annotations;
  using JetBrains.ReSharper.Psi.CSharp.Tree;
  using JetBrains.ReSharper.Psi.Tree;
  using Resharper.Abstractions.Actions;
  using Resharper.Abstractions.CodeDom.TreeNodes;

  /// <summary>Defines the <see cref="MethodExtensions"/> class.</summary>
  public static class MethodExtensions
  {
    #region Public Methods

    /// <summary>Gets the containing function.</summary>
    /// <param name="context">The context.</param>
    /// <returns>Returns the containing function.</returns>
    /// <exception cref="System.ArgumentNullException">context</exception>
    [CanBeNull]
    public static Method GetContainingMethod([NotNull] this ProviderContext context)
    {
      if (context == null)
      {
        throw new ArgumentNullException("context");
      }

      var result = context.InternalGetSelectedElement<IMethodDeclaration>();

      return result != null ? new Method(result) : null;
    }

    /// <summary>Gets the containing method.</summary>
    /// <param name="treeNode">The tree node.</param>
    /// <returns>Returns the containing method.</returns>
    public static Method GetContainingMethod([NotNull] this TreeNode treeNode)
    {
      if (treeNode == null)
      {
        throw new ArgumentNullException("treeNode");
      }

      var result = treeNode.InternalTreeNode.GetContainingNode<IMethodDeclaration>();

      return result != null ? new Method(result) : null;
    }

    /// <summary>Gets the method.</summary>
    /// <param name="treeNode">The tree node.</param>
    /// <returns>Returns the method.</returns>
    [CanBeNull]
    public static Method GetMethod([NotNull] this TreeNode treeNode)
    {
      var method = treeNode.InternalTreeNode as IMethodDeclaration;

      return method != null ? new Method(method) : null;
    }

    /// <summary>Creates the constant.</summary>
    /// <param name="context">The context.</param>
    /// <returns>Returns the constant.</returns>
    /// <exception cref="System.ArgumentNullException">context</exception>
    [CanBeNull]
    public static Method GetSelectedMethod([NotNull] this ProviderContext context)
    {
      if (context == null)
      {
        throw new ArgumentNullException("context");
      }

      var result = context.InternalGetSelectedElement<IMethodDeclaration>();
      if (result == null)
      {
        return null;
      }

      var selectedTreeNode = context.GetSelectedTreeNode();
      if (selectedTreeNode == null)
      {
        return null;
      }

      if (!result.GetNameDocumentRange().Contains(selectedTreeNode.GetDocumentRange()))
      {
        return null;
      }

      return new Method(result);
    }

    #endregion
  }
}